/*    file: H264Packager.cpp
 *    desc:
 * 
 * created: 2014-07-21 15:24:43
 *  author: zhengchuanjiang
 * company: 
 */

#include "stdafx.h"
#include "H264Packager.h"
#include "RtpHeader.h"

static uint8_t  getByteFiled(uint8_t value, int startBit, int nBits)
{
    uint8_t mask = (1 << nBits) - 1;
    return (value >> startBit)&mask;
}



H264Packager::H264Packager():
    m_file()
{

}

H264Packager::~H264Packager()
{
    close();
}

bool H264Packager::open(const char* filename)
{
    fopen_s(&m_file, filename, "wb");
    return (m_file != NULL);
}

bool H264Packager::isOpen()
{
    return (m_file != NULL);
}

void H264Packager::close()
{
    if (m_file)
    {
        fclose(m_file);
        m_file = NULL;
    }
}


static unsigned char s_startCode[] = { 0, 0, 0, 1};

void H264Packager::write(BYTE* ptr, UINT16 size)
{
    if (!isOpen())
    {
        return;
    }

	RTP_FIXED_HEADER* rtpHeader = (RTP_FIXED_HEADER*)ptr;

	if (size <= sizeof(RTP_FIXED_HEADER))
	{
		return;
	}

    BYTE* pPayload = ptr + sizeof(RTP_FIXED_HEADER);
    size_t  length = size - sizeof(RTP_FIXED_HEADER);

    if (rtpHeader->extension)
    {
        RTP_EXT_HEADER* extHeader = (RTP_EXT_HEADER*)pPayload;
        int extLength = ntohs(extHeader->length);

        uint8_t value = pPayload[4];
        int isFec = getByteFiled(value, 5, 3);

        if (isFec)
        {
            uint16_t seq = ntohs(rtpHeader->seq_no);
            printf("FEC Packet. seq: %d, length: %d\n", seq, length);
            return;
        }

        //printf("isFec: %d\n", isFec);


        pPayload += 4 + extLength * 4;
        length -= 4 + extLength * 4;

        if (length <= 0)
        {
            return;
        }
    }


    BYTE naluType = pPayload[0] & 0x1F;
    bool fullPacket = false;
    bool keyFrame = (naluType == 5);
    
    if (naluType == 28 || naluType == 29)
    {
        unsigned char startBit = pPayload[1]&0x80;
        unsigned char endBit = pPayload[1]&0x40;

        if( startBit )
        {
            naluType = ( pPayload[0] & 0xE0 ) | ( pPayload[1] & 0x1F );
            m_buffer.clear();
            m_buffer.write(s_startCode, sizeof(s_startCode));
            m_buffer.write(&naluType, 1);
        }
        else if (m_buffer.empty())
        {
            naluType = ( pPayload[0] & 0xE0 ) | ( pPayload[1] & 0x1F );
            m_buffer.clear();
            m_buffer.write(s_startCode, sizeof(s_startCode));
            m_buffer.write(&naluType, 1);
        }

        pPayload += 2;
        length -= 2;

        m_buffer.write(pPayload, length);

        if (endBit)
        {
            fullPacket = true;
            naluType = (m_buffer[sizeof(s_startCode)] & 0x1F);
            keyFrame = (naluType == 5);
        }
    }
    else
    {
        if (m_buffer.empty())
        {
            m_buffer.write(s_startCode, sizeof(s_startCode));
        }
        else
        {
            size_t len = m_buffer.length();
        }

        m_buffer.write(pPayload, length);
        fullPacket = true;
    }

    if (fullPacket)
    {
        fwrite(m_buffer.data(), 1, m_buffer.size(), m_file);
		fflush(m_file);

        m_buffer.clear();
    }

    
    
}
